/*
    Copyright © 2015-2019 The qTox Project Contributors

    This file is part of qTox, a Qt-based graphical interface for Tox.

    qTox is libre software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    qTox is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with qTox.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <algorithm>
#include <shared_mutex>
#include "corevideosource.h"

/**
 * @class CoreVideoSource
 * @brief A VideoSource that emits frames received by Core.
 */

/**
 * @var std::atomic_int subscribers
 * @brief Number of suscribers
 *
 * @var std::atomic_bool deleteOnClose
 * @brief If true, self-delete after the last suscriber is gone
 */

/**
 * @brief CoreVideoSource constructor.
 * @note Only CoreAV should create a CoreVideoSource since
 * only CoreAV can push images to it.
 */
CoreVideoSource::CoreVideoSource()
    : subscribers{0}
    , deleteOnClose{false}
    , stopped{false}
{
}

/**
 * @brief Makes a copy of the vpx_image_t and emits it as a new VideoFrame.
 * @param vpxframe Frame to copy.
 */
void CoreVideoSource::pushFrame(const vpx_image_t* vpxframe)
{
    if (stopped)
        return;
    std::unique_lock<std::mutex> locker(biglock);

    if (subscribers <= 0)
        return;
    //std::shared_ptr<utox_av_video_frame> yuvframe = std::make_shared<utox_av_video_frame>();
    //yuvframe->y = vpxframe->planes[0];
    //yuvframe->u = vpxframe->planes[1];
    //yuvframe->v = vpxframe->planes[2];
    //yuvframe->w = vpxframe->d_w;
    //yuvframe->h = vpxframe->d_h;
    std::shared_ptr<vpx_image_t> ptr((vpx_image_t*)vpxframe);
    frameAvailable(ptr);
}




void CoreVideoSource::subscribe()
{
    std::unique_lock<std::mutex> locker(biglock);
    ++subscribers;
}

void CoreVideoSource::unsubscribe()
{
    biglock.lock();
    if (--subscribers == 0) {
        if (deleteOnClose) {
            biglock.unlock();
            // DANGEROUS: No member access after this point, that's why we manually unlock
            delete this;
            return;
        }
    }
    biglock.unlock();
}

/**
 * @brief Setup delete on close
 * @param If true, self-delete after the last suscriber is gone
 */
void CoreVideoSource::setDeleteOnClose(bool newstate)
{
    std::unique_lock<std::mutex> locker(biglock);
    deleteOnClose = newstate;
}

/**
 * @brief Stopping the source.
 * @see The callers in CoreAV for the rationale
 *
 * Stopping the source will block any pushFrame calls from doing anything
 */
void CoreVideoSource::stopSource()
{
    std::unique_lock<std::mutex> locker(biglock);
    stopped = true;
    sourceStopped();
}

void CoreVideoSource::restartSource()
{
    std::unique_lock<std::mutex> locker(biglock);
    stopped = false;
}
